package cate.game.role.bag.exp;

import cate.common.table.d.GDAchievement;
import cate.common.table.res.achievement.row.AchievementExpRow;
import cate.common.util.GameResult;
import cate.game.attr.ExpsPowerAttrPart;
import cate.game.attr.PowerAttrPart;
import cate.game.client.msg.MergeMsgSender;
import cate.game.event.hero.HeroPowerChangeEvent;
import cate.game.play.support.PlayBuildContext;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.hero.Hero;
import cate.game.role.res.achievement.ExperienceInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.pattern.ICopiable;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExpsOn extends RoleDependent implements ICopiable<ExpsOn> {
    @JsonIgnore
    @Transient
    public transient Hero owner;

    @NoteField(value = "英雄身上的心得", detail = "Map<部位:Byte, 心得tid>")
    public Map<Byte, Integer> expMap;

    public void initialize(Hero owner, Role role){
        super.initialize(role);
        this.owner = owner;
        if(expMap == null){
            expMap = new HashMap<>();
        }
    }

    private GameResult<Void> preCheckOn(PlayBuildContext ctx, byte pos, int tid){
        GameResult<Void> r = new GameResult<>();
        ExperienceInfo expInfo = role.getRes().achievement.getExp(tid);
        if (expInfo == null) {
            return r.fail("该心得不存在");
        }
        if (!expInfo.active) {
            return r.fail("请先感悟心得");
        }
        if (StringUtils.isNotBlank(expInfo.onHeroUid)) {
            return r.fail("该心得已经被其他英雄装备了，请先卸下");
        }
        if (pos != 1 && pos != 2) {
            return r.fail("装备位置有误");
        }
        int limit = GDAchievement.EXP_EQUIP_LIMITS.getOrDefault(pos, 0);
        if (owner.getTpl(ctx).star < limit) {
            return r.fail("英雄星级未满足条件");
        }
        return r;
    }

    public GameResult<Byte> on(PlayBuildContext ctx, byte pos, int tid) {
        GameResult<Byte> r = new GameResult<>();
        GameResult<Void> checkRes = preCheckOn(ctx, pos, tid);
        if (!checkRes.ok()) {
            return r.fail(checkRes);
        }
        Integer old = expMap.get(pos);
        if (old != null) {
            ExperienceInfo oldInfo = role.getRes().achievement.getExp(old);
            if (oldInfo != null) {
                oldInfo.onHeroUid = null;
            }
        }
        ExperienceInfo expInfo = role.getRes().achievement.getExp(tid);
        expInfo.onHeroUid = owner.uid;
        expMap.put(pos, tid);
        role.getRes().achievement.noticeUpdate();
        return r;
    }

    public GameResult<Byte> off(PlayBuildContext ctx, byte pos) {
        GameResult<Byte> r = new GameResult<>();
        if (!expMap.containsKey(pos)) {
            return r.fail("该栏位没有装备心得噢");
        }
        int tid = expMap.get(pos);
        ExperienceInfo expInfo = role.getRes().achievement.getExp(tid);
        if (expInfo == null) {
            expMap.remove(pos);
            return r.fail("数据异常拉，请重新登录一下");
        }
        if (!StringUtils.equals(expInfo.onHeroUid, owner.uid)) {
            return r.fail("数据异常拉，找开发问问呢");
        }
        expInfo.onHeroUid = null;
        expMap.remove(pos);
        role.getRes().achievement.noticeUpdate();
        return r;
    }

    public PowerAttrPart getPowerAttrPart(PlayBuildContext ctx) {
        return new ExpsPowerAttrPart(ctx, this);
    }

    public List<Integer> getSkills(PlayBuildContext ctx) {
        List<Integer> skills = new ArrayList<>();
        if (!expMap.isEmpty()) {
            for (Integer tid : expMap.values()) {
                AchievementExpRow expRow = ctx.achievementExcel().exp.get(tid);
                if (expRow != null) {
                    skills.add(expRow.skill);
                }
            }
        }
        return skills;
    }

    @Override
    public ExpsOn copy() {
        ExpsOn cp = new ExpsOn();
        cp.expMap = SerializationUtils.clone((HashMap<Byte, Integer>) this.expMap);
        cp.initialize(this.owner, this.role);
        return cp;
    }

    public void offAll(Role role, Hero hero, MergeMsgSender sender, boolean updatePower) {
        boolean notice = false;
        for (int tid : expMap.values()) {
            ExperienceInfo expInfo = role.getRes().achievement.getExp(tid);
            if (expInfo != null) {
                expInfo.onHeroUid = null;
                notice = true;
            }
        }
        if (notice) {
            role.getRes().achievement.noticeUpdate();
        }
        expMap.clear();
        if (updatePower) {
            role.getBase().updatePower();
            publishEvent(role, new HeroPowerChangeEvent(hero.getRole(), hero));
        }
    }

    public void recheck() {
        boolean notice = false;
        for (Integer tid : expMap.values()) {
            ExperienceInfo expInfo = role.getRes().achievement.getExp(tid);
            if (expInfo != null) {
                expInfo.onHeroUid = this.owner.uid;
                notice = true;
            }
        }
        if (notice) {
            role.getRes().achievement.noticeUpdate();
        }
    }
}
